package com.cmc.cloud.cmclink.doc.service.impl.so;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.cmc.cloud.cmclink.doc.api.document.emums.ApprovalStatusEnum;
import com.cmc.cloud.cmclink.doc.api.document.emums.SpecialEnum;
import com.cmc.cloud.cmclink.doc.constants.errorconstant.AttachmentErrorCodeConstants;
import com.cmc.cloud.cmclink.doc.convert.AttachmentConvert;
import com.cmc.cloud.cmclink.doc.entity.AttachmentDO;
import com.cmc.cloud.cmclink.doc.entity.AttachmentTypeDO;
import com.cmc.cloud.cmclink.doc.entity.SpecialCargoApplyDO;
import com.cmc.cloud.cmclink.doc.mapper.AttachmentMapper;
import com.cmc.cloud.cmclink.doc.mapper.AttachmentTypeMapper;
import com.cmc.cloud.cmclink.doc.mapper.SpecialCargoApplyMapper;
import com.cmc.cloud.cmclink.doc.service.so.AttachmentService;
import com.cmc.cloud.cmclink.doc.vo.sovo.attachmentvo.*;
import com.cmes.framework.common.exception.util.ServiceExceptionUtil;
import com.cmes.framework.common.pojo.PageResult;
import com.cmes.framework.mybatis.core.query.LambdaQueryWrapperX;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;


/**
 * 订舱附件表 提单附件表 单证所有附件都保存在这张表 通过类型区分 Service 实现类
 *
 * @author 招商轮船-管理员
 */
@Service
@Validated
public class AttachmentServiceImpl implements AttachmentService {

    @Resource
    private AttachmentMapper attachmentMapper;
    @Resource
    private AttachmentTypeMapper attachmentTypeMapper;
    @Resource
    private SpecialCargoApplyMapper specialCargoApplyMapper;

    @Override
    public void createAttachment(AttachmentCreateReqVO createReqVO) {
        // 插入
        AttachmentDO attachment = AttachmentConvert.INSTANCE.convert(createReqVO);
        attachmentMapper.insert(attachment);
    }

    @Override
    public void createBatch(List<AttachmentCreateReqVO> createReqVOList) {
        // 插入
        List<AttachmentDO> list = AttachmentConvert.INSTANCE.convertBatch(createReqVOList);
        attachmentMapper.insertBatch(list);
    }

    @Override
    public List<AttachmentCountVO> selectSumByReferenceIds(List<Long> referenceIds, String referenceType) {
        if (CollectionUtil.isEmpty(referenceIds)) {
            return new ArrayList<>();
        }
        return attachmentMapper.selectSumByReferenceIds(referenceIds, referenceType);
    }

    @Override
    public void createOrUpdateAndDeleteBatch(Long referenceId, String referenceType, List<AttachmentUpdateReqVO> newList, List<AttachmentRespVO> oldList) {
        // 无效数据直接返回
        if (CollectionUtil.isEmpty(newList) && CollectionUtil.isEmpty(oldList)) {
            return;
        }
        // 默认值
        if (CollectionUtil.isEmpty(newList)) {
            newList = new ArrayList<>();
        }
        if (CollectionUtil.isEmpty(oldList)) {
            oldList = new ArrayList<>();
        }
        List<AttachmentUpdateReqVO> createList = new ArrayList<>();
        List<AttachmentUpdateReqVO> updateList = new ArrayList<>();
        // 历史数据
        Set<Long> oldIds = oldList.stream().map(AttachmentRespVO::getId).collect(Collectors.toSet());
        newList.forEach(e -> {
            if (e.getId() != null) {
                if (oldIds.contains(e.getId())) {
                    // 正常更新
                    updateList.add(e);
                    oldIds.remove(e.getId()); // 剩下的数据需要删除
                } else {
                    if (getAttachment(e.getId()) == null) {
                        // 数据更新非法
                        throw ServiceExceptionUtil.exception(AttachmentErrorCodeConstants.ATTACHMENT_NOT_EXISTS);
                    }
                }
            } else {
                e.setReferenceId(referenceId);
                e.setReferenceType(referenceType);
                createList.add(e);
            }
        });
        if (CollectionUtil.isNotEmpty(oldIds)) {
            // 没有匹配上的就是前端删除的
            attachmentMapper.deleteBatchIds(oldIds);
        }
        if (CollectionUtil.isNotEmpty(createList)) {
            List<AttachmentDO> attachmentCreateList = AttachmentConvert.INSTANCE.convertBatchUpdate(createList);
            attachmentMapper.insertBatch(attachmentCreateList);
        }
        if (CollectionUtil.isNotEmpty(updateList)) {
            List<AttachmentDO> attachmentUpdateList = AttachmentConvert.INSTANCE.convertBatchUpdate(updateList);
            attachmentMapper.updateBatch(attachmentUpdateList);
        }
    }

    @Override
    public void updateAttachment(AttachmentUpdateReqVO updateReqVO) {
        // 校验存在
        validateAttachmentExists(updateReqVO.getId());
        // 更新
        AttachmentDO updateObj = AttachmentConvert.INSTANCE.convert(updateReqVO);
        attachmentMapper.updateById(updateObj);
    }

    @Override
    public void createOrUpdateAttachment(AttachmentUpdateReqVO reqVO) {
        if (null == reqVO.getId()) {
            LambdaQueryWrapperX<AttachmentDO> queryWrapper = new LambdaQueryWrapperX<>();
            queryWrapper.eq(AttachmentDO::getReferenceId, reqVO.getReferenceId());
            queryWrapper.eq(AttachmentDO::getReferenceType, SpecialEnum.SPC.getValue());
            queryWrapper.eq(AttachmentDO::getAttachTypeCode, reqVO.getAttachTypeCode());
            List<AttachmentDO> attachmentDos = attachmentMapper.selectList(queryWrapper);
            if (CollectionUtil.isNotEmpty(attachmentDos)) {
                throw ServiceExceptionUtil.exception(AttachmentErrorCodeConstants.ATTACHMENT__EXISTED);
            }
            attachmentMapper.insert(AttachmentConvert.INSTANCE.convert(reqVO));
        } else {
            attachmentMapper.updateById(AttachmentConvert.INSTANCE.convert(reqVO));
        }
    }

    @Override
    public void deleteAttachment(Long id) {
        // 校验存在
        validateAttachmentExists(id);
        // 删除
        attachmentMapper.deleteById(id);
    }

    private void validateAttachmentExists(Long id) {
        if (attachmentMapper.selectById(id) == null) {
            throw ServiceExceptionUtil.exception(AttachmentErrorCodeConstants.ATTACHMENT_NOT_EXISTS);
        }
    }

    @Override
    public AttachmentDO getAttachment(Long id) {
        return attachmentMapper.selectById(id);
    }

    @Override
    public List<AttachmentDO> getAttachmentList(Collection<Long> ids) {
        return attachmentMapper.selectBatchIds(ids);
    }

    @Override
    public List<AttachmentRespVO> getAttachmentListAll(Long applyId, String applyType) {
        Map<String, AttachmentDO> codeTypeAttachments;
        if (null != applyId) {
            LambdaQueryWrapperX<AttachmentDO> queryWrapper = new LambdaQueryWrapperX<>();
            queryWrapper.eq(AttachmentDO::getReferenceId, applyId);
            queryWrapper.eq(AttachmentDO::getReferenceType, SpecialEnum.SPC.getValue());
            List<AttachmentDO> attachmentList = attachmentMapper.selectList(queryWrapper);
            codeTypeAttachments = attachmentList.stream().collect(Collectors.toMap(AttachmentDO::getAttachTypeCode, e -> e));
        } else {
            codeTypeAttachments = new HashMap<>(16);
        }

        List<AttachmentTypeDO> attachmentTypeDos = attachmentTypeMapper.selectList(new LambdaQueryWrapperX<AttachmentTypeDO>()
                .eq(AttachmentTypeDO::getUseModules, SpecialEnum.SPC.getValue()).eq(AttachmentTypeDO::getUseFunctions, applyType).orderByDesc(AttachmentTypeDO::getRequiredStatus));

        List<AttachmentRespVO> attachmentRespVos = new ArrayList<>();
        attachmentTypeDos.forEach(typeDO -> {
            AttachmentRespVO attachmentResp = new AttachmentRespVO();
            attachmentResp.setRequiredStatus(typeDO.getRequiredStatus());
            attachmentResp.setAttachTypeCode(typeDO.getAttatchTypeCode());
            attachmentResp.setAttachTypeNameCn(typeDO.getAttatchTypeCodeCn());
            attachmentResp.setAttachTypeNameEn(typeDO.getAttatchTypeCodeEn());
            AttachmentDO attachmentDO = codeTypeAttachments.get(typeDO.getAttatchTypeCode());
            if (null != attachmentDO) {
                attachmentResp.setId(attachmentDO.getId());
                attachmentResp.setReferenceType(attachmentDO.getReferenceType());
                attachmentResp.setFileId(attachmentDO.getFileId());
                attachmentResp.setAttachName(attachmentDO.getAttachName());
                attachmentResp.setFileFormat(attachmentDO.getFileFormat());
            }
            attachmentRespVos.add(attachmentResp);
        });
        if (null != applyId && SpecialEnum.AK.getValue().equals(applyType)) {
            SpecialCargoApplyDO applyDo = specialCargoApplyMapper.selectById(applyId);
            if (ApprovalStatusEnum.PRECONSENT.getValue().equals(applyDo.getApproveStatus())) {
                AttachmentRespVO attachmentResp = new AttachmentRespVO();
                attachmentResp.setPreConsent(Boolean.TRUE);
                attachmentResp.setRequiredStatus(Boolean.FALSE);
                attachmentResp.setAttachTypeCode(ApprovalStatusEnum.PRECONSENT.getValue());
                attachmentResp.setAttachTypeNameCn("装箱后的绑扎照片");
                attachmentResp.setAttachTypeNameEn("Photo of Post-Stowage Strapping");
                AttachmentDO attachmentDO = codeTypeAttachments.get(ApprovalStatusEnum.PRECONSENT.getValue());
                if (null != attachmentDO) {
                    attachmentResp.setId(attachmentDO.getId());
                    attachmentResp.setReferenceType(attachmentDO.getReferenceType());
                    attachmentResp.setFileId(attachmentDO.getFileId());
                    attachmentResp.setAttachName(attachmentDO.getAttachName());
                    attachmentResp.setFileFormat(attachmentDO.getFileFormat());
                }
                attachmentRespVos.add(attachmentResp);
            }

        }
        return attachmentRespVos;
    }


    @Override
    public PageResult<AttachmentDO> getAttachmentPage(AttachmentPageReqVO reqVO) {
        LambdaQueryWrapperX<AttachmentDO> queryWrapper = new LambdaQueryWrapperX<>();
        return attachmentMapper.selectPage(reqVO, queryWrapper);
    }

    public void deleteByReferenceIds(Collection<Long> referenceIds, String referenceType) {
        LambdaUpdateWrapper<AttachmentDO> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.in(AttachmentDO::getReferenceId, referenceIds);
        updateWrapper.in(AttachmentDO::getReferenceType, referenceType);
        attachmentMapper.delete(updateWrapper);
    }

    @Override
    public List<AttachmentDO> seleteByReferenceId(Long referenceId, String referenceType) {
        LambdaQueryWrapper<AttachmentDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(AttachmentDO::getReferenceId, referenceId);
        queryWrapper.eq(AttachmentDO::getReferenceType, referenceType);
        queryWrapper.orderByAsc(AttachmentDO::getId);
        return attachmentMapper.selectList(queryWrapper);
    }

    @Override
    public List<AttachmentDO> seleteByReferenceIds(List<Long> referenceIds, String referenceType) {
        LambdaQueryWrapper<AttachmentDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(AttachmentDO::getReferenceId, referenceIds);
        queryWrapper.eq(AttachmentDO::getReferenceType, referenceType);
        queryWrapper.orderByAsc(AttachmentDO::getId);
        return attachmentMapper.selectList(queryWrapper);
    }
}
